﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace Milan.Diagnostics
{
	/// <summary>
	/// A base class to be used to report changes in status for remote investigation of process internals.
	/// Derive from this class to report how the application is doing.
	/// Information is available in a hierarchical manner.
	/// </summary>
	public class StatusServer : Milan.Net.RpcServer
	{
		public delegate string ProviderDelegate(object invoker, string key);
		/// <summary>
		/// The pipe name is like so: \\milan.status.
		/// </summary>
		/// <param name="appmode"></param>
		public StatusServer(Milan.Deploy.Application application, string appmode) : base(application, GetPipeName(appmode), 10)
		{
			m_appmode = appmode ?? "";
			m_current = this;
		}
		private string m_appmode;
		public struct InvokerDelegate
		{
			public InvokerDelegate(ProviderDelegate _provider, object _invoker)
			{
				provider = _provider;
				invoker = _invoker;
			}
			public ProviderDelegate provider;
			public object invoker;
		}
		private Dictionary<string, InvokerDelegate> m_statusRoot = new Dictionary<string, InvokerDelegate>();
		/// <summary>
		/// Returns the official pipe name for the appmode/assembly
		/// </summary>
		/// <param name="appmode"></param>
		/// <returns></returns>
		public static string GetPipeName(string appmode=null)
		{
			m_pipename = StatusClient.GetPipeName(Path.GetFileName(Assembly.GetEntryAssembly().Location), appmode, Process.GetCurrentProcess().Id);
			return m_pipename;
		}
		public static string PipeName	{	get {	return m_pipename;	}	}
		private static string m_pipename;
		/// <summary>
		/// Tracks a particular value.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="root"></param>
		public void TrackValue(string key,object _invoker, ProviderDelegate _provider)
		{
			m_statusRoot[key] = new InvokerDelegate(_provider,_invoker);
		}
		public override string ProcessString(string command)
		{
			int i = command.IndexOf(' ');
			string op = command.Substring(0, i);
			string returns = "";
			try { 
				switch (op)
				{
					case "get":	// get provider_name subkey
						int j = command.IndexOf(' ', i + 1);
						var providerBlock = m_statusRoot[command.Substring(i, j)];
						providerBlock.provider.Invoke(providerBlock.invoker,command.Substring(j+1));
						break;
					case "dir":
						foreach (var provider in m_statusRoot)
							returns += provider.Key + "\n";
						break;
					case "quit":
						OnStop();
						returns = "true";
						break;
				}
			}
			catch(Exception ex)
			{
				returns = "err:" + ex.Message;
			}
			return returns;
		}
		/// <summary>
		/// This returns the last created StatusServer
		/// </summary>
		public static StatusServer Current
		{
			get
			{
				return m_current;
			}
		}
		private static StatusServer m_current;
		/// <summary>
		/// Find all the servers
		/// </summary>
		/// <returns></returns>
		public static string[] FindServers( string appmode, int id = -1 )
		{
			string nameStartsWith = @"\\.\pipe\milan.status." + Path.GetFileName(Assembly.GetEntryAssembly().Location) + "." + appmode;
			if(id>=0)
				nameStartsWith += "." + id.ToString();
			string[] listOfPipes = System.IO.Directory.GetFiles(@"\\.\pipe\").Where(x=>x.StartsWith(nameStartsWith)).ToArray();
			return listOfPipes;
		}
	}
}
